/**
 * @file SelectionTool.cpp
 *
 * @date 26/12/2011
 * @author Tales 
 *
 */

#include "SelectionTool.hpp"
#include "Editor.hpp"
#include "../Graphics.hpp"
#include "../common/util.hpp"
#include <cmath>
#include "../model/AreaCommand.hpp"
#include "../model/Picture.hpp"
#include "../model/PasteSurfaceCommand.hpp"

namespace yep
{

SelectionTool::SelectionTool()
{

}

void SelectionTool::start()
{
	drawing = false;
	moving = false;
	Editor &editor = getEditor();
	SDL_FillRect(editor.getPreview(), NULL, 0x0);
	selectedArea = (SDL_Rect){0,0,0,0};
}

void SelectionTool::end()
{
	if (selectedArea.w > 0 && selectedArea.h > 0)
		fireCommand();
	getEditor().unselect();
}

void SelectionTool::pressed(pair<int, int> pos, bool leftButton, bitset<5> state)
{
	if (leftButton && !drawing)
	{
		if (pos.first >= selectedArea.x && pos.second >= selectedArea.y && pos.first < selectedArea.x + selectedArea.w
				&& pos.second < selectedArea.y + selectedArea.h)
		{
			moving = true;
			p1 = make_pair(selectedArea.x, selectedArea.y);
			p2 = make_pair(p1.first + selectedArea.w - 1, p1.second + selectedArea.h - 1);
			Editor &editor = getEditor();
			SDL_Surface * preview = editor.getPreview();
			if (state[MOD_3])
			{
				getPicture().addCommand(
						new AreaCommand(FILLED_RECT, p1, p2, editor.getColor(), editor.getCurrentLayer()));
			}
			Graphics g(preview);
			g.blit(editor.getSelected(), p1);
		}
		else
		{
			Editor &editor = getEditor();
			if (selectedArea.w > 0 && selectedArea.h > 0)
			{
				fireCommand();
				SDL_Rect changedArea = toSDL_Rect(p1, p2);
				SDL_FillRect(editor.getPreview(), &changedArea, 0x0);
			}
			drawing = true;
			p1 = p2 = pos;
			Graphics g(editor.getPreview());
			g.setColor(editor.getColor());
			g.drawPixel(pos);
		}
	}
}

void SelectionTool::released(pair<int, int> pos, bool leftButton, bitset<5> state)
{
	if (leftButton)
	{
		Editor &editor = getEditor();
		SDL_Surface *preview = editor.getPreview();
		Graphics g(preview);
		if (drawing)
		{
			drawing = false;
			//Obtendo area selecionada
			selectedArea = toSDL_Rect(p1, pos);
			SDL_FillRect(preview, &selectedArea, 0x0);
			editor.selectFromRect(selectedArea);
			//Desenhando seleção
			drawRect(g, p1, pos);
		}
		else if (moving)
		{
			moving = false;
			SDL_Surface *selectedSurface = editor.getSelected();
			g.blit(selectedSurface, p1);
			drawRect(g, p1, p2);
		}
	}
	else
	{
		fireCommand();
		getEditor().unselect();
		selectedArea = toSDL_Rect(p1, p2);
		SDL_Surface *preview = getEditor().getPreview();
		SDL_FillRect(preview, &selectedArea, 0x0);
		selectedArea =
		{	0,0,0,0};
	}
}

void SelectionTool::moved(pair<int, int> pos, pair<int, int> offset, std::bitset<5> state)
{
	typedef void (Graphics::*AreaMethod)(const pair<int, int> &p1, const pair<int, int> &p2);
	if (state[BUTTON_LEFT])
	{
		Editor &editor = getEditor();
		SDL_Rect changedArea = toSDL_Rect(p1, p2);
		SDL_FillRect(editor.getPreview(), &changedArea, 0x00ffFFff);
		if (drawing)
		{
			p2 = pos;
			Graphics g(editor.getPreview());
			drawRect(g, p1, pos);
		}
		else if (moving)
		{
			p1 = make_pair(p1.first + offset.first, p1.second + offset.second);
			p2 = make_pair(p2.first + offset.first, p2.second + offset.second);
			selectedArea.x += offset.first;
			selectedArea.y += offset.second;
			Graphics g(editor.getPreview());
			g.blit(editor.getSelected(), p1);
			drawRect(g, p1, p2);
		}
	}
}

namespace frameCounter
{

extern size_t currentFrame;

} // namespace frameCounter

void SelectionTool::drawRect(Graphics &g, const pair<int, int> &p1, const pair<int, int> &p2)
{
	size_t offset = frameCounter::currentFrame >> 2;
	int minX = min(p1.first, p2.first);
	int minY = min(p1.second, p2.second);
	int maxX = max(p1.first, p2.first);
	int maxY = max(p1.second, p2.second);
	for (int i = minX; i <= maxX; ++i)
	{
		Color c = ((offset + i + p1.second) / 4) % 2 ? Color::WHITE : Color::BLACK;
		g.setColor(c);
		g.drawPixel(make_pair(i, p1.second));
		c = ((offset + i + p2.second) / 4) % 2 ? Color::WHITE : Color::BLACK;
		g.setColor(c);
		g.drawPixel(make_pair(i, p2.second));
	}

	for (int i = minY; i <= maxY; ++i)
	{
		Color c = ((offset + i + p1.first) / 4) % 2 ? Color::WHITE : Color::BLACK;
		g.setColor(c);
		g.drawPixel(make_pair(p1.first, i));
		c = ((offset + i + p2.first) / 4) % 2 ? Color::WHITE : Color::BLACK;
		g.setColor(c);
		g.drawPixel(make_pair(p2.first, i));
	}
}

void SelectionTool::fireCommand()
{
	Editor &editor = getEditor();
	SDL_Surface *selectedSurface = editor.getSelected();
	++selectedSurface->refcount;
	getPicture().addCommand(new PasteSurfaceCommand(selectedSurface, p1, editor.getColor(), editor.getCurrentLayer()));
}

void SelectionTool::notifyPaste()
{
	Editor &editor = getEditor();
	SDL_Surface *selectedSurface = editor.getSelected();
	selectedArea =
	{	0, 0, (Uint16)selectedSurface->w, (Uint16)selectedSurface->h};
	p1 = make_pair(0, 0);
	p2 = make_pair(selectedArea.w - 1, selectedArea.h - 1);
	drawing = false;
	moving = false;
	SDL_Surface * preview = editor.getPreview();
	Graphics g(preview);
	g.blit(editor.getSelected(), p1);
	drawRect(g, p1, p2);
}

} /* namespace yep */
